package cn.hehuoren.quartz.service.impl;

import cn.hehuoren.core.exception.BusinessException;
import cn.hehuoren.core.utils.DateUtil;
import cn.hehuoren.quartz.dao.QuartzManagerMapper;
import cn.hehuoren.quartz.model.QuartzManager;
import cn.hehuoren.quartz.service.ISchedulerService;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

/**
 * 任务调度Service
 * @author John
 */
@Service
@com.alibaba.dubbo.config.annotation.Service
public class SchedulerServiceImpl implements ISchedulerService {
	public static final Logger logger = LoggerFactory.getLogger(SchedulerServiceImpl.class);
	@Resource
	private Scheduler quartzScheduler;

	@Resource
	private QuartzManagerMapper quartzManagerMapper;
	
	@Override
	public boolean interrupt(QuartzManager quartz)
			throws UnableToInterruptJobException {
		JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
		return this.quartzScheduler.interrupt(jobKey);
	}
	
	@Override
	public Date registScheduleJob(QuartzManager quartz, Class jobClass) throws Exception {
		JobDetail jobDetail = JobBuilder.newJob(jobClass).withDescription(quartz.getDtlDescription()).withIdentity(quartz.getDtlJobName(),
				quartz.getDtlJobGroup()).build();
		if(this.quartzScheduler.checkExists(jobDetail.getKey())){
			throw new BusinessException("任务名称已存在，请更改任务名称后重新提交 ");
		}
		//设置参数
		jobDetail.getJobDataMap().putAll(quartz.getJobDataMap());
		Date dtrigStartTime = DateUtil.parse(quartz.getTrigStartTimeStr(), "yyyy-MM-dd");
		Date dtrigEndTime = DateUtil.parse(quartz.getTrigEndTimeStr(), "yyyy-MM-dd");
		//触发器
		CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().withDescription(quartz.getDtlDescription()).
				startAt(dtrigStartTime).endAt(dtrigEndTime).withIdentity(quartz.getDtlJobName()+"_trigger", quartz.getDtlJobGroup()).withSchedule(
				CronScheduleBuilder.cronSchedule(quartz.getCronCronExpression())).build();
		//监听器 待扩展
//		JobListener jobListener = new SimpleJobListener("SimpleJobListener"); 
		return this.quartzScheduler.scheduleJob(jobDetail, trigger);
	}

	@Override
	public Date registScheduleJobUpdate(QuartzManager quartz, Class jobClass)
			throws SchedulerException, ClassNotFoundException {
		JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
		//先删除,如果class不存在,则需要强制删除
		try {
			this.quartzScheduler.deleteJob(jobKey);//移除job
		} catch (Exception e) {
			logger.error(String.format("正常删除job失败,尝试从数据库中删除,正常删除失败原因:%s", e));
			deleteJobFromDB(quartz);
		}
		//创建jobDetail
		JobDetail jobDetail = JobBuilder.newJob(jobClass).withDescription(quartz.getDtlDescription()).withIdentity(quartz.getDtlJobName(), quartz.getDtlJobGroup()).build();
		//设置参数
		jobDetail.getJobDataMap().putAll(quartz.getJobDataMap());
		Date dtrigStartTime = DateUtil.parse(quartz.getTrigStartTimeStr(), "yyyy-MM-dd");
		Date dtrigEndTime = DateUtil.parse(quartz.getTrigEndTimeStr(), "yyyy-MM-dd");
		
		//再增加，增加前判断分组是否改变，如果改变重新定义jobdetail
		CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().withDescription(quartz.getDtlDescription()).startAt(dtrigStartTime).endAt(dtrigEndTime)
		.withIdentity(quartz.getDtlJobName()+"_trigger", quartz.getDtlJobGroup()).withSchedule(
			CronScheduleBuilder.cronSchedule(quartz.getCronCronExpression())).build();
		this.quartzScheduler.scheduleJob(jobDetail, trigger);
		if("PAUSED".equals(quartz.getTrigTriggerState())){
			this.pauseJob(quartz);
		}
		return null;
	}

	@Override
	public boolean deleteJob(QuartzManager quartz) throws SchedulerException {
		boolean isDeleted = false;
		try {
			JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
			isDeleted = this.quartzScheduler.deleteJob(jobKey);
		} catch (Exception e) {
			logger.error(String.format("正常删除job失败,尝试从数据库中删除,正常删除失败原因:%s", e));
			deleteJobFromDB(quartz);
		}
		return isDeleted;
	}

	@Override
	public void pauseJob(QuartzManager quartz) throws SchedulerException {
		JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
		this.quartzScheduler.pauseJob(jobKey);
	}

	@Override
	public void resumeJob(QuartzManager quartz) throws SchedulerException {
		JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
		this.quartzScheduler.resumeJob(jobKey);
	}

	@Override
	public void pauseJob() throws SchedulerException {
		this.quartzScheduler.pauseAll();
	}

	@Override
	public void resumeJob() throws SchedulerException {
		this.quartzScheduler.resumeAll();
	}

	@Override
	public void triggerJob(QuartzManager quartz) throws SchedulerException {
		JobKey jobKey = new JobKey(quartz.getDtlJobName(), quartz.getDtlJobGroup());
		this.quartzScheduler.triggerJob(jobKey);
	}

	@Override
	public boolean getStartStatus() throws SchedulerException {
		return this.quartzScheduler.isStarted();
	}

	@Override
	public String getSchedulerName() throws SchedulerException {
		return this.quartzScheduler.getSchedulerName();
	}
	@Override
	public void shutdownScheduler() throws SchedulerException {
		//等待正在执行的调度器执行完成后停止调度器
		 this.quartzScheduler.shutdown(true);
	}
	
	@Override
    public JobDetail getJobDetailByKey(String dtlJobName, String dtlJobGroup) throws SchedulerException {
	   JobKey jobKey = new JobKey(dtlJobName, dtlJobGroup);
	   return quartzScheduler.getJobDetail(jobKey);
	}
	
	@Transactional
    public boolean deleteJobFromDB(QuartzManager quartz)
            throws SchedulerException {
        logger.info(String.format("------从数据库中删除job[%s]开始-------", quartz.getDtlJobName()));
        quartz.setTrigTriggerName(String.format("%s%s", quartz.getDtlJobName(),"_trigger"));
        quartz.setDtlJobGroup(quartz.getDtlJobGroup());
        quartz.setTrigTriggerGroup(quartz.getDtlJobGroup());
        //注意删除顺序,否则会因数据库约束导致删除失败
        quartzManagerMapper.deleteQrtzCronTriggers(quartz);
        quartzManagerMapper.deleteQrtzTriggers(quartz);
        quartzManagerMapper.deleteQrtzJobDetails(quartz);
        logger.info(String.format("------从数据库中删除job[%s]结束-------", quartz.getDtlJobName()));
        return true;
    }

	@Override
	public void sayHello() {
		logger.info("hello world !");
	}
}
